package com.jili;

import com.jili.annotation.*;
import com.jili.aspect.LoggingAspect;
import com.jili.controller.UserController;
import com.jili.factory.ProxyFactory;
import com.jili.service.UserService;
import com.sun.net.httpserver.HttpServer;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;

/**
 *  ClassName: MySpringAopApplication
 *  Package com.jili
 *  Description:
 *  @Author: 廖继礼
 *  @Create: 2025/6/5
 *  @Version: v1.0
 *
 */
public class MySpringAopApplication {

    private final Map<String, Object> beans = new HashMap<>();

    private final Map<String, Object> originalBeans = new HashMap<>();

    private final Map<String, Method> urlMappings = new HashMap<>();

    private final Map<String, Object> controllerBeans = new HashMap<>();

    // AOP相关存储
    private final Map<String, List<Method>> beforeAdvices = new ConcurrentHashMap<>();

    private final Map<String, List<Method>> afterAdvices = new ConcurrentHashMap<>();


    public MySpringAopApplication(Class<?> configClass) throws Exception {
        // 1. 扫描并创建bean
        Package pkg = configClass.getPackage();
        scanPackage(pkg.getName());

        // 应用AOP代理
        applyAspects();

        // 依赖注入
        injectDependencies();

        // 建立URL映射
        setupUrlMapping();
    }

    private void setupUrlMapping() {
        for (Map.Entry<String, Object> entry : controllerBeans.entrySet()) {
            Object controller = entry.getValue();
            Class<?> controllerClass = controller.getClass();
            // 如果是代理对象，获取原始类
            if (controller instanceof Proxy) {
                InvocationHandler handler = Proxy.getInvocationHandler(controller);
                controllerClass = handler.getClass();
            }
            for (Method method : controllerClass.getDeclaredMethods()) {
                if (method.isAnnotationPresent(RequestMapping.class)) {
                    String url = method.getAnnotation(RequestMapping.class).value();
                    urlMappings.put(url, method);
                }
            }
        }
    }

    private void injectDependencies() throws Exception {
        for (Object bean : beans.values()) {
            // 如果是代理对象，获取原始目标
            Object target = (bean instanceof Proxy) ?
                    Proxy.getInvocationHandler(bean) : bean;

            for (Field field : target.getClass().getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    Object dependency = beans.get(field.getType().getSimpleName());
                    field.setAccessible(true);
                    field.set(target, dependency);
                }
            }
        }
    }

    private void applyAspects() throws Exception {
        for (Map.Entry<String, Object> entry : originalBeans.entrySet()) {
            String beanName = entry.getKey();
            Object bean = entry.getValue();
            Class<?> beanClass = bean.getClass();

            // 检查是否需要应用切面
            for (String pointcut : beforeAdvices.keySet()) {
                if (beanClass.getName().contains(pointcut)) {
                    System.out.println("Applying AOP to: " + beanName);
                    beans.put(beanName, ProxyFactory.createProxy(
                            bean,
                            beforeAdvices.get(pointcut),
                            afterAdvices.getOrDefault(pointcut, Collections.emptyList())
                    ));
                }
            }
        }
    }

    private void scanPackage(String packageName) throws Exception {
        for (Class<?> clazz : getClassesInPackage(packageName)) {
            // 只处理具体类（非接口/非抽象类）
            if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) {
                if (clazz.isAnnotationPresent(Component.class) ||
                        clazz.isAnnotationPresent(Aspect.class)) {

                    Object bean = createBean(clazz);
                    String beanName = clazz.getSimpleName();
                    beans.put(beanName, bean);
                    originalBeans.put(beanName, bean);

//                    // 注册接口类型
//                    registerInterfaceTypes(clazz);

                    if (clazz.isAnnotationPresent(Aspect.class)) {
                        registerAspect(clazz, bean);
                    }

                    if (clazz.getSimpleName().contains("Controller")) {
                        controllerBeans.put(beanName, bean);
                    }
                }
            }
        }
    }

    private void registerInterfaceTypes(Class<?> clazz) {
        for (Class<?> intf : clazz.getInterfaces()) {
            beans.put(intf.getSimpleName(), beans.get(clazz.getSimpleName()));
        }
    }


    public void startServer(int port) throws IOException {
        HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);

        server.createContext("/", exchange -> {
            String path = exchange.getRequestURI().getPath();
            Method handler = urlMappings.get(path);

            if (handler != null) {
                try {
                    // 找到对应的控制器实例
                    Object controller = controllerBeans.get(
                            handler.getDeclaringClass().getSimpleName()
                    );

                    // 执行控制器方法
                    Object result = handler.invoke(controller);

                    // 处理响应
                    exchange.sendResponseHeaders(200, 0);
                    try (OutputStream os = exchange.getResponseBody()) {
                        if (handler.isAnnotationPresent(ResponseBody.class)) {
                            os.write(result.toString().getBytes());
                        } else {
                            os.write(("<h1>" + result + "</h1>").getBytes());
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    exchange.sendResponseHeaders(500, 0);
                }
            } else {
                String response = "404 Not Found: " + path;
                exchange.sendResponseHeaders(404, response.length());
                try (OutputStream os = exchange.getResponseBody()) {
                    os.write(response.getBytes());
                }
            }
        });

        server.setExecutor(Executors.newCachedThreadPool());
        server.start();
        System.out.println("Server started on port " + port);
    }

    private void registerAspect(Class<?> aspectClass, Object aspectBean) {
        Aspect aspect = aspectClass.getAnnotation(Aspect.class);
        String pointCut = aspect.value();
        for (Method method : aspectClass.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Before.class)) {
                Before before = method.getAnnotation(Before.class);
                if (before.value().equals(pointCut)) {
                    beforeAdvices.computeIfAbsent(pointCut, k -> new ArrayList<>()).add(method);
                }
            }
            if (method.isAnnotationPresent(After.class)) {
                After after = method.getAnnotation(After.class);
                if (after.value().equals(pointCut)) {
                    afterAdvices.computeIfAbsent(pointCut, k -> new ArrayList<>()).add(method);
                }
            }
        }
    }

    private Object createBean(Class<?> clazz) throws Exception {
        return clazz.getDeclaredConstructor().newInstance();
    }


    /**
     * 模拟包扫描
     * @param pkgName
     * @return
     */
    private List<Class<?>> getClassesInPackage(String pkgName) {
        return Arrays.asList(
                UserService.class,
                UserController.class,
                LoggingAspect.class,
                SecurityException.class,
                AppConfig.class
        );
    }
}
